package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.login.TsLogin;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.account.AccountDeductVo;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.prometheus.client.Collector;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Override
    public void orderPaySuccess(String orderNo) {
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);
        if (null == orderInfo || SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())){
            return;
        }
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        this.updateById(orderInfo);
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());
        userPaidRecordVo.setItemIdList(orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList()));
        userPaidRecordVo.setOrderNo(orderNo);

        userInfoFeignClient.savePaidRecord(userPaidRecordVo);


    }

    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, String orderStatus, Long userId) {

        IPage<OrderInfo> iPage = orderInfoMapper.selectUserPage(orderInfoPage,orderStatus,userId);
        iPage.getRecords().stream().forEach(orderInfo->{
            orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay())?"余额支付":"在线支付");
            orderInfo.setOrderStatusName(SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())?"未支付":SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())?"已支付":"已取消");

        });


        return iPage;
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        OrderInfo orderInfo = this.getOrderInfoByOrderNo(orderNo);

        orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay())?"余额支付":"在线支付");


        return orderInfo;
    }

    @Override
    public void orderCancel(String orderNo) {
        OrderInfo orderInfo = getOrderInfoByOrderNo(orderNo);
        if (null != orderInfo && SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus())){
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);

            orderInfoMapper.updateById(orderInfo);
        }


    }

    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        orderInfo.setOrderDetailList(orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId,orderInfo.getId())));
        return orderInfo;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {

        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        map.put("payWay","");
        SignHelper.checkSign(map);

        String tradeNo = orderInfoVo.getTradeNo();

        String tradeNoKey = "tradeNo:"+userId+":"+tradeNo;

//        Boolean result = this.redisTemplate.opsForValue().setIfAbsent(tradeNoKey, tradeNo, 1, TimeUnit.DAYS);
//        if (!result){
//            throw new RuntimeException("重复提交订单");
//        }

//        String redisTradeNo = (String)this.redisTemplate.opsForValue().get(tradeNoKey);
//        if (!tradeNo.equals(redisTradeNo)){
//            throw new RuntimeException("重复提交订单");
//        }
//        this.redisTemplate.delete(tradeNoKey);
        String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(scriptText);
        Long count = (Long)this.redisTemplate.execute(script, Arrays.asList(tradeNoKey), tradeNo);
        if (count==0){
            throw new RuntimeException("重复提交订单");
        }
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");

        if(!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            this.saveOrder(userId,orderNo,orderInfoVo);
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_ORDER,MqConst.ROUTING_CANCEL_ORDER,orderNo,MqConst.CANCEL_ORDER_DELAY_TIME);
        }else {
            this.saveOrder(userId,orderNo,orderInfoVo);
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName());

            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);

            if (200 != result.getCode()){
                throw new RuntimeException("扣减余额失败");
            }
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfo.setUpdateTime(new Date());

            orderInfoMapper.update(orderInfo, new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo,orderNo));


            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setUserId(userId);


            List<Long> itemIdList = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIdList);

            Result userResult =  userInfoFeignClient.savePaidRecord(userPaidRecordVo);

            if (200!=userResult.getCode()){
                throw new RuntimeException("保存用户购买记录失败");
            }

        }

        return orderNo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(Long userId, String orderNo, OrderInfoVo orderInfoVo) {
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo,orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(orderNo);
        orderInfoMapper.insert(orderInfo);

        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList)){
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo,orderDetail);
                orderDetail.setOrderId(orderInfo.getId());

                orderDetailMapper.insert(orderDetail);

            }
        }

        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)){
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                OrderDerate orderDerate = new OrderDerate();

                BeanUtils.copyProperties(orderDerateVo,orderDerate);
                orderDerate.setOrderId(orderInfo.getId());

                orderDerateMapper.insert(orderDerate);

            }
        }


    }

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {

        // 初始化金额相关变量
        BigDecimal originalAmount = new BigDecimal("0.00");
        BigDecimal derateAmount = new BigDecimal("0.00");
        BigDecimal orderAmount = new BigDecimal("0.00");
        
        // 初始化订单详情和优惠详情列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        
        // 根据商品类型处理订单逻辑
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())){
            // 处理专辑类型商品的订单逻辑
            Long albumId = tradeVo.getItemId();
            // 判断用户是否购买过该专辑
            Result<Boolean> result = userInfoFeignClient.isPaidAlbum(albumId);
            Assert.notNull(result,"远程调用判断用户是否购买过专辑失败");
            if (result.getData()){
                throw  new RuntimeException("用户购买过专辑");
            }
        
            // 获取专辑信息
            Result<AlbumInfo> infoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(infoResult, "远程调用专辑信息失败");
            AlbumInfo albumInfo = infoResult.getData();
            Assert.notNull(albumInfo,"远程调用获取专辑信息失败");
        
            // 设置原价
            originalAmount= albumInfo.getPrice();
            // 获取用户信息
            Result<UserInfoVo> infoVoResult = userInfoFeignClient.getUserInfo(userId);
            Assert.notNull(infoResult,"远程调用获取用户信息失败");
            UserInfoVo userInfoVo = infoVoResult.getData();
            Assert.notNull(userInfoVo,"远程调用获取用户信息失败");
            // 根据用户是否为VIP计算优惠金额
            if (0==userInfoVo.getIsVip()||(1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))){
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1"))!=0){
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"),2,BigDecimal.ROUND_HALF_UP);
                }
            }else {
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1"))!=0){
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"),2,BigDecimal.ROUND_HALF_UP);
                }
            }
            // 计算订单金额
            orderAmount = originalAmount.subtract(derateAmount);
            // 构建订单详情对象并添加到列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVoList.add(orderDetailVo);
        
            // 如果有优惠金额，则构建优惠详情对象并添加到列表
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            if (derateAmount.compareTo(new BigDecimal("0"))!=0){
        
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
        
            }
        
        
        }else if(SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())){
            // 处理音轨类型商品的订单逻辑
            if (tradeVo.getTrackCount()<0){
                throw new RuntimeException("购买集数不能小于0");
            }
//            Result<TrackInfoVo> trackInfoVoResult =  trackInfoFeignClient.getTrackInfo(tradeVo.getItemId());
//            Assert.notNull(trackInfoVoResult,"远程调用获取声音对象失败");
//            TrackInfoVo trackInfo = trackInfoVoResult.getData();
//            Assert.notNull(trackInfo,"远程调用获取声音对象失败");
//
//            Long albumId = trackInfo.getAlbumId();
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(),tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult,"远程调用获取声音对象失败");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList,"远程调用获取声音对象失败");

            Result<AlbumInfo> infoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(infoResult,"远程调用专辑对象失败");
            AlbumInfo albumInfo = infoResult.getData();
            Assert.notNull(albumInfo,"远程调用专辑对象失败");

            originalAmount = tradeVo.getTrackCount()==0 ? albumInfo.getPrice() :albumInfo.getPrice().multiply(new BigDecimal(tradeVo.getTrackCount()));
            orderAmount = originalAmount;



            orderDetailVoList = trackInfoList.stream().map(trackInfo1->{
                OrderDetailVo orderDetailVo = new OrderDetailVo();

                orderDetailVo.setItemId(trackInfo1.getId());
                orderDetailVo.setItemName(trackInfo1.getTrackTitle());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemUrl(trackInfo1.getCoverUrl());
                return orderDetailVo;
            }).collect(Collectors.toList());



        }else {
            // 处理其他类型商品的订单逻辑
            Long itemId = tradeVo.getItemId();
            // 获取VIP服务配置信息
            Result<VipServiceConfig> serviceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(itemId);
            Assert.notNull(serviceConfigResult,"远程调用获取vip_service_config对应大数据失败");
            VipServiceConfig vipServiceConfig = serviceConfigResult.getData();
            Assert.notNull(vipServiceConfig,"远程调用获取vip_service_config对应大数据失败");
        
            // 设置原价、优惠金额和订单金额
            originalAmount = vipServiceConfig.getPrice();
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());
            orderAmount = vipServiceConfig.getDiscountPrice();
        
            // 构建订单详情对象并添加到列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(itemId);
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVoList.add(orderDetailVo);
        
            // 如果有优惠金额，则构建优惠详情对象并添加到列表
            if (derateAmount.compareTo(new BigDecimal("0"))!=0){
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setRemarks("vip折扣");
                orderDerateVoList.add(orderDerateVo);
        
            }
        
        }
        
        // 构建订单信息对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 生成交易编号并确保其唯一性
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        String tradeNoKey = "tradeNo:" + userId+":"+tradeNo;
        this.redisTemplate.opsForValue().setIfAbsent(tradeNoKey,tradeNo,15, TimeUnit.MINUTES);
        
        // 设置订单信息
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        
        // 添加时间戳并生成签名
        long timestamp = SignHelper.getTimestamp();
        orderInfoVo.setTimestamp(timestamp);
        String jsonStr = JSON.toJSONString(orderInfoVo);
        String sign =  SignHelper.getSign(JSON.parseObject(jsonStr, Map.class));
        orderInfoVo.setSign(sign);
        
        // 返回订单信息对象
        return orderInfoVo;
    }
}
